﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.IO;
using System.Diagnostics;


namespace scavenger.winforms
{
    //TODO:
    //1. MAKE SURE THAT ONLY ONE INSTANCE OF THE PROGRAM IS RUNNING AT A TIME.
    //2. PLAY A NICE BEEPING SOULD LIKE DOWNTHEMALL DOES.
    //3. MAKE USE OF THE PROGRESS BAR ON TOP RIGHT.

    public partial class MainForm : Form
    {
        public static List<HttpDownload> HttpDownloads = new List<HttpDownload>();
        //public static MainForm instance = null;

        public MainForm()
        {
            InitializeComponent();
            //SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            //this.DoubleBuffered = true;
            lvwMain.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(lvwMain, true, null);
            //instance = this;
            Bitmap tbmp = (Bitmap)Properties.Resources.ResourceManager.GetObject("scavenger_logo");
            //StackFrame sf = new StackFrame();
            //Type tp = typeof(Properties.Resources);
            //this.BackgroundImage= (Image)tp.GetProperty("scavenger_logo").GetValue(null, null);
        }

        private void fillHttpDownloads(DownloadStatusEnum status,bool ignoreStatus)
        {
            var progress = 0.0;//average progress
            for(int i=0;i<HttpDownloads.Count;i++)
            {
                HttpDownload dn = HttpDownloads[i];
                //lvwMain.Items.Add(dn.url.AbsolutePath,dn.url.AbsolutePath);
                if (dn.Status == status || ignoreStatus)
                {
                    ListViewItem li;
                    if (lvwMain.Items.ContainsKey(dn.Url.OriginalString + dn.FileName))
                        li = lvwMain.Items[dn.Url.OriginalString + dn.FileName];
                    else
                    {
                        li = lvwMain.Items.Add(dn.Url.OriginalString + dn.FileName, dn.FileName, -1);
                        li.SubItems.AddRange(new string[] { "0", "0", "0", "0", "0" });
                    }

                    var size = dn.Size;
                    var sizeKB = dn.SizeInKB;
                    var bytesRead = dn.BytesRead;
                    var speed = dn.Speed;
                    var percentProgress = (size == 0 ? 0 : (float)bytesRead / size * 100);

                    if ((bytesRead / 1024) > 1024)
                    {
                        li.SubItems[1].Text = Math.Round(bytesRead / 1024.00 / 1024.00, 2) + " MB (" + Math.Round(percentProgress, 0) + "%)"; //progress
                    }
                    else
                    {
                        li.SubItems[1].Text = Math.Round(bytesRead / 1024.00, 2) + " KB (" + Math.Round(percentProgress, 0) + "%)"; //progress
                    }

                    if (dn.SizeInKB > 1024)
                    {
                        li.SubItems[2].Text = String.Format("{0:0.00}MB", sizeKB / 1024.00); //total size
                    }
                    else
                    {
                        li.SubItems[2].Text = String.Format("{0:0.00}KB", (float)sizeKB); //total size
                    }

                    //calculate remaining time
                    double mins = (speed == 0) ? 0 : (sizeKB - (bytesRead / 1024.00)) / (float)speed / 60;

                    progress += percentProgress;

                    li.SubItems[3].Text = string.Format("{0:0.00} mins", mins); //time-remaining
                    li.SubItems[4].Text = String.Format("{0:0.00} KB/S", dn.Speed); //speed
                    li.SubItems[5].Text = dn.Status.ToString(); //status

                    li.ImageIndex = imageList1.Images.IndexOfKey("FILTER." + dn.Status.ToString().ToUpper());
                    li.Tag = i;
                }
                else { 
                    //remove item from list if it already exists
                    if (lvwMain.Items.ContainsKey(dn.Url.OriginalString + dn.FileName))
                        lvwMain.Items.RemoveByKey(dn.Url.OriginalString + dn.FileName);
                }
            }

            if (!(toolStripProgressBar1.ProgressBar == null))
            {
                if (HttpDownloads.Count > 0)
                {
                    toolStripProgressBar1.Value = (int)progress / HttpDownloads.Count;
                }
                else
                {
                    toolStripProgressBar1.Value = 0;
                }
            }
            //Application.DoEvents();
        }

        private void refreshCurrentView()
        {
            if (lvwMain.SelectedItems.Count > 0)
            {
                lvwMain_SelectedIndexChanged(null, null);
            }

            if (tvwMain.SelectedNode == null) return;

            switch (tvwMain.SelectedNode.Name)
            {
                case "CAT_ALL":
                    fillHttpDownloads(DownloadStatusEnum.Running, true);
                    break;
                case "CAT_HTTP":
                    fillHttpDownloads(DownloadStatusEnum.Running,true);
                    break;
                case "FILTER_ALL":
                    fillHttpDownloads(DownloadStatusEnum.Running,true);
                    break;
                case "FILTER_RUNNING":
                    fillHttpDownloads(DownloadStatusEnum.Running,false);
                    break;
                case "FILTER_PAUSED":
                    fillHttpDownloads(DownloadStatusEnum.Paused,false);
                    break;
                case "FILTER_STOPPED":
                    fillHttpDownloads(DownloadStatusEnum.Stopped,false);
                    break;
                case "FILTER_COMPLETED":
                    fillHttpDownloads(DownloadStatusEnum.Completed,false);
                    break;
                default:
                    if (tvwMain.SelectedNode.Parent ==null)
                    {
                        //This is one of the root nodes, so show all rows.
                        fillHttpDownloads(DownloadStatusEnum.Running,true);
                    }
                    break;
            }
        }




        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox about = new AboutBox();
            about.ShowDialog();
        }

        private void toolStripButtonAbout_Click(object sender, EventArgs e)
        {
            aboutToolStripMenuItem_Click(null, null);
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            //Load settings from data file, or set default settings.
            if (!SettingsManager.ReadSettings())
            {
                SettingsManager.DefineSetting("proxy_server", "");
                SettingsManager.DefineSetting("proxy_port", "0");
                SettingsManager.DefineSetting("proxy_username", "");
                SettingsManager.DefineSetting("proxy_password", "");
            }

            tvwMain.Nodes.Add("BY_CATEGORY", "By Category", imageList1.Images.IndexOfKey("FOLDER.CLOSED"));
            tvwMain.Nodes["BY_CATEGORY"].Nodes.Add("CAT_ALL", "All", imageList1.Images.IndexOfKey("FOLDER.OPEN"), imageList1.Images.IndexOfKey("FOLDER.OPEN"));
            tvwMain.Nodes["BY_CATEGORY"].Nodes.Add("CAT_HTTP", "HTTP/HTTPS", imageList1.Images.IndexOfKey("CAT.HTTP"), imageList1.Images.IndexOfKey("CAT.HTTP"));

            tvwMain.Nodes.Add("BY_FILTER", "By Filters", imageList1.Images.IndexOfKey("FOLDER.CLOSED"), imageList1.Images.IndexOfKey("FOLDER.CLOSED"));
            tvwMain.Nodes["BY_FILTER"].Nodes.Add("FILTER_ALL", "All", imageList1.Images.IndexOfKey("FOLDER.OPEN"), imageList1.Images.IndexOfKey("FOLDER.OPEN"));
            tvwMain.Nodes["BY_FILTER"].Nodes.Add("FILTER_RUNNING", "Running", imageList1.Images.IndexOfKey("FILTER.RUNNING"), imageList1.Images.IndexOfKey("FILTER.RUNNING"));
            tvwMain.Nodes["BY_FILTER"].Nodes.Add("FILTER_PAUSED", "Paused", imageList1.Images.IndexOfKey("FILTER.PAUSED"), imageList1.Images.IndexOfKey("FILTER.PAUSED"));
            tvwMain.Nodes["BY_FILTER"].Nodes.Add("FILTER_STOPPED", "Stopped", imageList1.Images.IndexOfKey("FILTER.STOPPED"), imageList1.Images.IndexOfKey("FILTER.STOPPED"));
            tvwMain.Nodes["BY_FILTER"].Nodes.Add("FILTER_COMPLETED", "Completed", imageList1.Images.IndexOfKey("FILTER.COMPLETED"), imageList1.Images.IndexOfKey("FILTER.COMPLETED"));

            tvwMain.ExpandAll();
            tvwMain.SelectedNode =  tvwMain.Nodes["BY_CATEGORY"].Nodes[0];

            lvwMain.Columns[lvwMain.Columns.Count - 1].Width = -2;

            //read all paused downloads from disk
            string httpfile = AppDomain.CurrentDomain.BaseDirectory + "HttpDownloads.dat";
            if (File.Exists(httpfile))
            {
                using (FileStream fs = new FileStream(httpfile,FileMode.Open, FileAccess.Read))
                {
                    HttpDownloads=(List<HttpDownload>)Utils.DeserializeFromBinary(fs);
                    fs.Close();
                    //call OnDeserialize()
                    foreach (Download dn in HttpDownloads)
                    {
                        dn.OnDeserialize();
                    }
                    //refresh listview
                    //fillHttpDownloads(DownloadStatusEnum.Running, true);
                    refreshCurrentView();
                }
            }

            this.notifyIcon1.Icon = this.Icon;

            runAtStartupToolStripMenuItem.Checked = CheckStartup();

            timer1.Start();
        }

        private void toolStripButtonAdd_Click(object sender, EventArgs e)
        {
            AddDownloadBox addBox = new AddDownloadBox();
            addBox.Show();
        }

        private void openInExplorerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (lvwMain.SelectedItems.Count > 0)
            {
                Point pt = new Point(mnuListView.Left, mnuListView.Top);
                pt = splitContainer1.Panel2.PointToClient(pt);
                ListViewItem li = lvwMain.GetItemAt(pt.X,pt.Y);
                string fname=HttpDownloads[(int) li.Tag].FullFileName;
                string dname= Path.GetDirectoryName(fname);
                //System.Diagnostics.Process.Start("Explorer.exe", @"/select,""" + fname + "\"");
                Process.Start("Explorer.exe", "\"" + dname + "\"");
            }
        }

        private void toolStripButtonPause_Click(object sender, EventArgs e)
        {
            if (lvwMain.SelectedItems.Count > 0)
            {
                HttpDownload dn = HttpDownloads[(int)lvwMain.SelectedItems[0].Tag];
                dn.Pause();
                lvwMain_SelectedIndexChanged(null, null);
            }
        }

        private void lvwMain_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lvwMain.SelectedItems.Count > 0)
            {
                HttpDownload dn=HttpDownloads[(int)lvwMain.SelectedItems[0].Tag];
                switch (dn.Status)
                { 
                    case DownloadStatusEnum.Running:
                        toolStripButtonStart.Enabled = false;
                        toolStripButtonStop.Enabled = true;
                        toolStripButtonPause.Enabled = true;
                        toolStripButtonRemove.Enabled = true;
                        break;
                    case DownloadStatusEnum.Paused:
                        toolStripButtonStart.Enabled = true;
                        toolStripButtonStop.Enabled = true;
                        toolStripButtonPause.Enabled = false;
                        toolStripButtonRemove.Enabled = true;
                        break;
                    default:
                        toolStripButtonStart.Enabled = false;
                        toolStripButtonStop.Enabled = false;
                        toolStripButtonPause.Enabled = false;
                        toolStripButtonRemove.Enabled = true;
                        break;
                }
                lvwMain.ContextMenuStrip = mnuListView;
            }
            else 
            {
                toolStripButtonStart.Enabled = false;
                toolStripButtonStop.Enabled = false;
                toolStripButtonPause.Enabled = false;
                toolStripButtonRemove.Enabled = false;
                lvwMain.ContextMenuStrip = null;
            }

            startToolStripMenuItem.Enabled = toolStripButtonStart.Enabled;
            stopToolStripMenuItem.Enabled = toolStripButtonStop.Enabled;
            pauseToolStripMenuItem.Enabled = toolStripButtonPause.Enabled;
            removeToolStripMenuItem.Enabled = toolStripButtonRemove.Enabled;

        }

        private void toolStripButtonStart_Click(object sender, EventArgs e)
        {
            if (lvwMain.SelectedItems.Count > 0)
            {
                HttpDownload dn = HttpDownloads[(int)lvwMain.SelectedItems[0].Tag];
                dn.Resume();
                lvwMain_SelectedIndexChanged(null, null);
            }
        }

        private void lvwMain_Resize(object sender, EventArgs e)
        {
            lvwMain.Columns[lvwMain.Columns.Count - 1].Width = -2;
        }

        private void logsToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {

            foreach (Download dn in HttpDownloads)
            {
                if (dn.Status==DownloadStatusEnum.Running)
                {
                    if (MessageBox.Show("You have Active Downloads running. Sure you want to quit", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                    {
                        e.Cancel = true;
                        return;
                    }
                    else {
                        break;
                    }
                }
            }

            if (e.Cancel == false)
            {
                lblStatus.Text = "Stopping all downloads.";
                timer1.Stop();
                StopAllDownloads();
            }

        }

        private void StopAllDownloads()
        {
            foreach (Download dn in HttpDownloads)
            {
                if (dn.Status == DownloadStatusEnum.Running)
                    dn.Pause();
                else if (dn.IsRunning())
                    dn.Stop();
            }

            //save all paused downloads to disk
            if (HttpDownloads.Count > 0)
            {
                using (FileStream fs = new FileStream(AppDomain.CurrentDomain.BaseDirectory + "HttpDownloads.dat", FileMode.Create, FileAccess.Write))
                {
                    Utils.SerializeToBinary(HttpDownloads, fs);
                    fs.Close();
                }
            }
        }

        private void toolStripButtonViewLogs_Click(object sender, EventArgs e)
        {
            Process.Start("notepad.exe", "\"" + AppDomain.CurrentDomain.BaseDirectory + "scavenger.log\"");
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            refreshCurrentView();
        }

        private void toolStripButtonMoveUp_Click(object sender, EventArgs e)
        {
            if (lvwMain.SelectedItems.Count > 0 && lvwMain.SelectedItems[0].Index>0)
            {
                ListViewItem currItem = lvwMain.SelectedItems[0];
                int curr = currItem.Index;
                currItem.Remove();
                lvwMain.Items.Insert(curr - 1, currItem);

            }
        }

        private void toolStripButtonMoveDown_Click(object sender, EventArgs e)
        {
            if (lvwMain.SelectedItems.Count > 0 && lvwMain.SelectedItems[0].Index < (lvwMain.Items.Count-1))
            {
                ListViewItem currItem = lvwMain.SelectedItems[0];
                int curr = currItem.Index;
                currItem.Remove();
                lvwMain.Items.Insert(curr + 1, currItem);
            }
        }

        private void tvwMain_AfterSelect(object sender, TreeViewEventArgs e)
        {
            timer1_Tick(null, null);
        }

        private void toolStripButtonRemove_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Remove this download", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                return;

            if (lvwMain.SelectedItems.Count > 0)
            {
                HttpDownload dn= HttpDownloads[(int)lvwMain.SelectedItems[0].Tag];
                if (dn.Status != DownloadStatusEnum.Running)
                {
                    dn.Stop();
                }
                else {
                    return;
                }

                if (MessageBox.Show("Sure you want to remove this download", Application.ProductName, MessageBoxButtons.YesNo) == DialogResult.No)
                    return;

                HttpDownloads.Remove(dn);
                lvwMain.Items.Remove(lvwMain.SelectedItems[0]);
            }
        }

        private void removeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            toolStripButtonRemove_Click(null, null);
        }

        private void stopToolStripMenuItem_Click(object sender, EventArgs e)
        {
            
        }

        private void startToolStripMenuItem_Click(object sender, EventArgs e)
        {
            toolStripButtonStart_Click(null, null);
        }

        private void pauseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            toolStripButtonPause_Click(null, null);
        }

        private void toolStripButtonStop_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Sure you want to stop this download", Application.ProductName, MessageBoxButtons.YesNo,MessageBoxIcon.Question) == DialogResult.No)
                return;

            if (lvwMain.SelectedItems.Count > 0)
            {
                HttpDownload dn = HttpDownloads[(int)lvwMain.SelectedItems[0].Tag];
                dn.Stop();

                //HttpDownloads.Remove(dn);
                //lvwMain.Items.Remove(lvwMain.SelectedItems[0]);
            }
        }

        private void toolStripButtonSchedule_Click(object sender, EventArgs e)
        {
            AddDownloadBox addBox = new AddDownloadBox();
            addBox.ShowScheduled = true;
            addBox.Show();
        }

        private void toolStripButtonSettings_Click(object sender, EventArgs e)
        {
            timer1.Stop();
            
            SettingsManager settingsmanager = new SettingsManager();
            settingsmanager.ShowDialog();
            settingsmanager = null;

            timer1.Start();
        }

        private void hashCalculatortToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new HashCalculator().ShowDialog();
        }

        private void lvwMain_KeyPress(object sender, KeyPressEventArgs e)
        {
        }

        private void lvwMain_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
                if (toolStripButtonRemove.Enabled)
                toolStripButtonRemove_Click(null, null);
        }

        private void notifyIcon1_DoubleClick(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Normal;
            this.ShowInTaskbar = true;
            //this.BringToFront();
        }

        private void MainForm_Resize(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.ShowInTaskbar = false;
            }
        }

        private void bandwidthMeterToolStripMenuItem_Click(object sender, EventArgs e)
        {
            BandwidthMeter bandwidthmeter = new BandwidthMeter();
            bandwidthmeter.ShowDialog();
        }

        private void exitToolStripMenuItem_Click_1(object sender, EventArgs e)
        {
            this.Close();
        }

        private void lvwMain_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
            }
        }

        private bool CheckStartup()
        {
            string startupDir = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
            string linkFilename = startupDir + "\\" + Application.ProductName + ".url";

            if (File.Exists(linkFilename))
                return true;
            else
                return false;
        }

        private void CreateShortcut(string linkName,bool delete)
        {
            //string startupDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonStartup);
            string startupDir = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
            string linkFilename = startupDir + "\\" + linkName + ".url";

            if (delete)
            {
                if(File.Exists(linkFilename)) File.Delete(linkFilename);
                return;
            }

            using (StreamWriter writer = new StreamWriter(linkFilename))
            {
                string app = System.Reflection.Assembly.GetExecutingAssembly().Location;
                writer.WriteLine("[InternetShortcut]");
                writer.WriteLine("URL=file:///" + app);
                writer.WriteLine("IconIndex=0");
                string icon = app.Replace('\\', '/');
                writer.WriteLine("IconFile=" + icon);
                writer.Flush();
            }
        }

        private void runAtStartupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (runAtStartupToolStripMenuItem.Checked)
            {
                runAtStartupToolStripMenuItem.Checked = false;
                //remove from startup
                CreateShortcut(Application.ProductName, true);
            }
            else 
            {
                runAtStartupToolStripMenuItem.Checked = true;
                //run at startup
                CreateShortcut(Application.ProductName, false);
            }
        }
    }
}
